"""author: wenyao
   data: 2020/10/26
   project: ludingji
"""
# def func01():
#     print("this is function 01")
#
# func01()
# func01()
# func01()
# func01()

#  参数的形式
# 参数在函数定义的圆括号对内指定，用逗号分割。
# 形参：函数中的参数名称为形参
# 实参：提供给函数调用的值称为实参

# def bmi(s, w):
#     bmi = w /s**2
#     s = s+10
#     return bmi
#
# s = 1.58
# w = 45
# b1 = bmi(s, w)
# print(b1)
# print(s)

#####参数的分类（按照定义分，形参）#########
#必选参数/位置参数
#默认参数/关键字参数
#可变长位置参数
#可变长关键字参数

#注意使用顺序

#位置参数
# def funcsum(a,b):
#     return a+b
#
# funcsum(1,2)

# def func02(name, age, sex):
#     print(f"my name is {name}, age is {age}, sex is {sex}")
#
# func02("wenyao",18,"f")
# func02("f",18,"wenyao")
#func02("f",18)

######默认参数###############
# def func03(name, age, sex="f"):
#     print(f"my name is {name}, age is {age}, sex is {sex}")
#
# func03("wenyao",18)
# func03("wenyao",18,'testm')
#
# ###########对于实参而言，位置参数要放在关键字参数的前面#######
# func03("wenyao",age=19,sex = "testm")
# #func03(19,name="wenyao",sex="testm")  #错误
# #如果都是用关键字参数传递值，那关键字参数的顺序是可以打乱的
# func03(sex="testm",name="wenyao",age=20)

############对于形参而言，必选参数的定义要放在默认参数的前面###########
# def func03(name = "wenyao", age, sex):
#     print(f"my name is {name}, age is {age}, sex is {sex}")

#可变位置参数
def myargs(*num):
    print(*num)
    print(type(num), num)

def myargs_test(num):
    print(type(num),num)

#packing  and  unpacking
#packing
#1,2 ===>元组 (1,2)
#unpacking
#*num ---> unpacking -->1 2 3 4
#a = [1,2,3,4]  -->1,2,3,4
#a = {"test1":1,"test2":2}  ==> test1=1,test2=2
# myargs()
# myargs(1,2)
# myargs(1,2,3)
# myargs(1,2,3,4)
# myargs_test((1,2))
# myargs_test((1,2,3))

#可变长关键字参数
#packing --> a=1,b=2  -->packing -->字典 {"a":1,"b":2}
#unpacking -->a=1,b=2,c=3
# def myargs2(**num):
#     sum = 0
#     print(num)
#     for i in num.values():
#         sum += i
#     print(sum)
#
# myargs2(a=1,b=2,c=3,d=4)
# myargs2(a=2,b=3)

#  参数定义的先后
# 最佳方式：mysun(必选参数, *args, 默认参数, **kargs)
# 不是每项都需要，如果需要的话，要按上述顺序


#########函数的return语句###########
#退出函数，并且可以返回结果
#一旦执行到return，就退出，后面语句不会执行
#如果没有return的话，默认返回None。如果return后面不接任何表达式，也是返回None
#return可以返回多值
# def maxnum_test(x,y):
#     print("return语句。。。。")
#     if x > y:
#         print("return x")
#         return x,y
#     else:
#         print("return y")
#         return
#     print("return 语句 end")
#
# t1 = maxnum_test(2,3)
# print(t1)
# t2 = maxnum_test(4,3)
# print(t2)
# t3, t4 = maxnum_test(4,3)
# print(t3)
# print(t4)

###########匿名函数###############
#不需要创建函数名
#只能有一个表达式，不用写return，该表达式的结果就是返回值
#定义规则：
  #lambda  args1,args2 : args1 + args2

# def add(a,b):
#     return a+b
#
# add2 = lambda a,b : a+b
# print(add(2,3))
# print(add2(2,3))

# comp = lambda x, y: x if x>y else y
# print(comp(3,4))
# print(comp(46,3))

#########递归函数##############
#自己调用自己，形成循环
# 出口条件，即递归“什么时候结束”，这个通常在递归函数的开始就写好
# 可以通过递归调用来缩小问题规模，且新问题与原问题有着相同的形式
# def factorial_func(n):
#     factor_num = 1
#     for i in range(1,n+1):
#         factor_num *=i
#     return factor_num
#
# print(factorial_func(4))

# def factorial_func2(n):
#     if n == 1:
#         return 1
#     return n * factorial_func2(n-1)
# print(factorial_func2(4))
# print(factorial_func2(998))
#####尽量避免使用递归，除非没有更好的算法或者某种特定情况下使用。
#每次递归都会保存在内存中，非常占用内存，并且效率低
#python中默认递归深度为999

##########函数的参数传递############
#本质是传递引用
#传递不可变数据类型
# def  f(x):
#     x = 100
#     print(x)
# x = 1
# f(x)
# print(x)

#传递可变数据类型
# def f(x):
#     x[0] =100
#     print(x)
# a = [1,2,3]
# f(a)
# print(a)

#参数定义时，尽量避免定义成一个可变对象
# def f(a=[]):
#     a.append(1)
#     print(a)
#
# f()
# f()
# f()

# def f(b):
#     b["test"] = 1
#     print(b)
#
# b = {"test":2,"test2":3}
# f(b)
# print(b)

#########变量的作用域#################
#使用global关键字编程一个全局变量
# def f():
#     global x
#     x = 5
# x = 1
# f()
# print(x)

#变量名解析：LEGB原则
#   LEGB作用域查找原则，当引用一个变量时，python按照以下顺序依次进行查找：
# 从本地变量中 -> Local（function）函数内部
# 在任意上层函数的作用域 -> Enclosing function locals 嵌套函数内部
# 在全局作用域 -> Global（module）
# 最后在内置作用域中查找 -> Built-in（python）

#如果都没有找到，就会报错

# def f():
#     #x=4
#     def f2():
#         #x = 3
#         x.append("4")
#         print(x)
#     f2()
# x = [1,2,3]
# f()
# print(x)

######工厂函数与内建函数##############
# 函数与方法
# 函数是大家的函数，方法是类的方法
# 与类和实例无绑定关系的function都属于函数（function）
# 与类和实例有绑定关系的function都属于方法（method）

#print是函数
